package j.util.web;

import j.util.DES;
import j.util.New;
import j.util.StringUtils;
import j.util.exception.ApplicationException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.Serializable;
import java.util.Map;

/**
 * User: jason
 * Date: 13-7-18 下午2:20
 */
public class DesSessionKey implements Serializable {
    public static final int SESSION_DES_CRYPT_KEY_LENGTH = 32;
    /**
     * 操作读key
     */
    public static final String OPT_READ_KEY = "read";
    /**
     * 操作编辑key
     */
    public static final String OPT_EDIT_KEY = "edit";
    /**
     * 操作删除key
     */
    public static final String OPT_DELETE_KEY = "delete";
    /**
     * 对模块操作中的ID的加密,每次登录密码是不一样的,是存放在session中的
     */
    public static final String SESSION_DES_CRYPT_KEY = "session_des_crypt_key";

    private Object lockObject = new Object();

    /**
     * key为optKey,value为des key
     */
    private Map<String,String> sessionKeys = New.map();

    private String publicDesCryptKey = StringUtils.randomString(SESSION_DES_CRYPT_KEY_LENGTH);

    public String getDesCryptKey(){
        return publicDesCryptKey;
    }

    public String getDesCryptKey(String optKey){
        if(StringUtils.isNullOrEmpty(optKey)){
            return publicDesCryptKey;
        }
        if(sessionKeys.containsKey(optKey)){
            return sessionKeys.get(optKey);
        }
        String key;
        synchronized (lockObject){
            key = sessionKeys.get(optKey);
            if(StringUtils.isNullOrEmpty(key)){
                key = StringUtils.randomString(SESSION_DES_CRYPT_KEY_LENGTH);
                sessionKeys.put(optKey, key);
            }
        }
        return key;
    }

    public static String getDesCryptKey(HttpServletRequest request,String optKey){
        HttpSession session = request.getSession(false);
        DesSessionKey dsk = (DesSessionKey)session.getAttribute(SESSION_DES_CRYPT_KEY);
        if(null == dsk){
            throw new ApplicationException("无法从当前对话中获取密钥信息,请重新登录试试看!");
        }
        return dsk.getDesCryptKey(optKey);
    }

    /**
     * 对data进行加密
     * @param request
     * @param data
     * @param optKey
     * @return
     */
    public static String encrypt(HttpServletRequest request,String data,String optKey){
        HttpSession session = request.getSession(false);
        DesSessionKey dsk = (DesSessionKey)session.getAttribute(SESSION_DES_CRYPT_KEY);
        if(null == dsk){
            synchronized (DesSessionKey.class){
                dsk = (DesSessionKey)session.getAttribute(SESSION_DES_CRYPT_KEY);
                if(null == dsk){
                    dsk = new DesSessionKey();
                    session.setAttribute(SESSION_DES_CRYPT_KEY,dsk);
                }
            }
        }
        String key = dsk.getDesCryptKey(optKey);
        return DES.encrypt(data, key);
    }

    public static String decrypt(HttpServletRequest request,String data,String optKey){
        if(StringUtils.isNotEmpty(data)){
            String cryptKey = DesSessionKey.getDesCryptKey(request, optKey);
            if(StringUtils.isNullOrEmpty(cryptKey)){
                throw new ApplicationException("无法在用户会话中获取DES密钥,请重新登录.");
            }
            data = DES.decrypt(data, cryptKey);
            if(StringUtils.isNullOrEmpty(data)){
                throw new ApplicationException("无法将指定的数据[%s]转换为正确的ID值,请重试!",data);
            }
        }else{
            return null;
        }
        return data;
    }

    public static String getId(HttpServletRequest request,String key,String optKey){
        String s = request.getParameter(key);
        if(StringUtils.isNotEmpty(s)){
            String cryptKey = DesSessionKey.getDesCryptKey(request, optKey);
            if(StringUtils.isNullOrEmpty(cryptKey)){
                throw new ApplicationException("无法在用户会话中获取DES密钥,请重新登录.");
            }
            s = DES.decrypt(s, cryptKey);
            if(StringUtils.isNullOrEmpty(s)){
                throw new ApplicationException("无法将key为[%s]转换为正确的ID值,请重试!",key);
            }
        }else{
            return null;
        }
        return s;
    }
}
